home *** CD-ROM | disk | FTP | other *** search
/ Almathera Ten Pack 2: CDPD 1 / Almathera Ten on Ten - Disc 2: CDPD 1.iso / pd / 051-075 / 068 / mg1b / extend.c < prev    next >
C/C++ Source or Header  |  1995-03-13  |  10KB  |  394 lines

  1. /*
  2.  *        Extended (M-X) commands.
  3.  */
  4. #include    "def.h"
  5.  
  6. /*
  7.  * This function modifies the keyboard
  8.  * binding table, by adjusting the entries in the
  9.  * big "bindings" array. Most of the grief deals with the
  10.  * prompting for additional arguments.
  11.  */
  12. /*ARGSUSED*/
  13. bindtokey(f, n, k) {
  14.     register int    s;
  15.     register SYMBOL    *sp;
  16.     int        c;
  17.     char        xname[NXNAME];
  18.  
  19.     if (kbdmop == NULL)
  20.         ewprintf("Set key globally: ") ;
  21.     c = (int) getkey(0);
  22.     if ((s=eread("Set key %c to command: ", xname, NXNAME, EFNEW|EFFUNC,
  23. #ifdef VARARGS
  24.              c
  25. #else
  26.              (char *) &c, (char *) NULL
  27. #endif
  28.              )) != TRUE)
  29.         return (s);
  30.     if ((sp=symlookup(xname)) == NULL) {
  31.         ewprintf("[No match]");
  32.         return (FALSE);
  33.     }
  34.     binding[(KEY) c] = sp;            /* rebind new.        */
  35.     return (TRUE);
  36. }
  37.  
  38. /*
  39.  * User function to unbind keys. Just call the unbind we already have. 
  40.  */
  41. /*ARGSUSED*/
  42. unsetkey(f, n, k) {
  43.     register KEY    key;
  44.     
  45.     if (kbdmop == NULL) ewprintf("Unset key globally: ") ;
  46.     key = getkey(0);
  47.     if (key == (KCTRL|'G') || key == (KCTLX|KCTRL|'G')
  48.     || key == (KMETA|KCTRL|'G')) {
  49.         (VOID) ctrlg(FALSE, 1, KRANDOM);
  50.         return ABORT;
  51.     }
  52.     binding[key] = NULL;
  53.     return TRUE;
  54. }
  55.  
  56. /*
  57.  * Extended command. Call the message line
  58.  * routine to read in the command name and apply autocompletion
  59.  * to it. When it comes back, look the name up in the symbol table
  60.  * and run the command if it is found and has the right type.
  61.  * Print an error if there is anything wrong.
  62.  */
  63. /*ARGSUSED*/
  64. extend(f, n, k) {
  65.     register SYMBOL    *sp;
  66.     register int    s;
  67.     char        xname[NXNAME];
  68.  
  69.     if (f == FALSE)
  70.         s = eread("M-x ", xname, NXNAME, EFNEW|EFFUNC
  71. #ifndef VARARGS
  72.              , (char *) NULL
  73. #endif
  74.              ) ;
  75.     else
  76.         s = eread("%d M-x ", xname, NXNAME, EFNEW|EFFUNC, 
  77. #ifdef    VARARGS
  78.              n
  79. #else
  80.              (char *) &n, (char *) NULL
  81. #endif
  82.              ) ;
  83.     if (s != TRUE) return (s);
  84.     if ((sp=symlookup(xname)) != NULL)
  85.         return ((*sp->s_funcp)(f, n, KRANDOM));
  86.     ewprintf("[No match]");
  87.     return FALSE;
  88. }
  89.  
  90. /*
  91.  * Read a key from the keyboard, and look it
  92.  * up in the binding table. Display the name of the function
  93.  * currently bound to the key. Say that the key is not bound
  94.  * if it is indeed not bound, or if the type is not a
  95.  * "builtin". This is a bit of overkill, because this is the
  96.  * only kind of function there is.
  97.  */
  98. /*ARGSUSED*/
  99. desckey(f, n, k) {
  100.     register SYMBOL    *sp;
  101.     register KEY    c;
  102.  
  103.     if (kbdmop == NULL) ewprintf("Describe key briefly: ");
  104.     c = getkey(0);
  105.     if (kbdmop != NULL) return TRUE;
  106.     if ((sp=binding[c]) == NULL)
  107.         ewprintf("%c is undefined", (int) c);
  108.     else
  109.         ewprintf("%c runs the command %s", (int) c, sp->s_name);
  110.     return (TRUE);
  111. }
  112.  
  113. /*
  114.  * This function creates a table, listing all
  115.  * of the command keys and their current bindings, and stores
  116.  * the table in the standard pop-op buffer (the one used by the
  117.  * directory list command, the buffer list command, etc.). This
  118.  * lets MicroEMACS produce it's own wall chart. The bindings to
  119.  * "ins-self" are only displayed if there is an argument.
  120.  */
  121. /*ARGSUSED*/
  122. wallchart(f, n, k) {
  123.     register int    key;
  124.     register SYMBOL    *sp;
  125.     register char    *cp1;
  126.     register char    *cp2;
  127.     BUFFER        *bp;
  128.     char        buf[64];
  129.  
  130.     bp = bfind("*Help*", TRUE);
  131.     if (bclear(bp) != TRUE)            /* Clear it out.    */
  132.         return TRUE;
  133.     for (key=0; key<NKEYS; ++key) {        /* For all keys.    */
  134.         sp = binding[key];
  135.         if (sp != NULL
  136.         && (f!=FALSE
  137.         || strcmp(sp->s_name, "self-insert-command")!=0)) {
  138.             keyname(buf, key);
  139.             cp1 = &buf[0];        /* Find end.        */
  140.             while (*cp1 != 0)
  141.                 ++cp1;
  142.             while (cp1 < &buf[32])    /* Goto column 32.    */
  143.                 *cp1++ = ' ';                
  144.             cp2 = sp->s_name;    /* Add function name.    */
  145.             while (*cp1++ = *cp2++)
  146.                 ;
  147.             if (addline(bp, buf) == FALSE)
  148.                 return (FALSE);
  149.         }
  150.     }
  151.     return popbuf(bp) == NULL ? FALSE : TRUE;
  152. }
  153.  
  154. #ifdef    STARTUP
  155. /*
  156.  * Define the commands needed to do startup-file processing.
  157.  * This code is mostly a kludge just so we can get startup-file processing.
  158.  *
  159.  * If you're serious about having this code, you should rewrite it.
  160.  * To wit: 
  161.  *    It has lots of funny things in it to make the startup-file look
  162.  *    like a GNU startup file; mostly dealing with parens and semicolons.
  163.  *    This should all vanish.
  164.  *
  165.  *    It uses the same buffer as keyboard macros. The fix is easy (make
  166.  *    a new function "execmacro" that takes a pointer to char and
  167.  *    does what ctlxe does on it. Make ctlxe and excline both call it.)
  168.  *    but would slow down the non-micro version.
  169.  *
  170.  * We define eval-expression because it's easy. It's pretty useless,
  171.  * since it duplicates the functionality of execute-extended-command.
  172.  * All of this is just to support startup files, and should be turned
  173.  * off for micros.
  174.  */
  175.  
  176. /*
  177.  * evalexpr - get one line from the user, and run it. Identical in function
  178.  *    to extend, but easy.
  179.  */
  180. /*ARGSUSED*/
  181. evalexpr(f, n, k) {
  182.     register int    s;
  183.     char        exbuf[NKBDM];
  184.  
  185.     if ((s = ereply("Eval: ", exbuf, NKBDM)) != TRUE)
  186.         return s;
  187.     return excline(exbuf);
  188. }
  189. /*
  190.  * evalbuffer - evaluate the current buffer as line commands. Useful
  191.  *    for testing startup files.
  192.  */
  193. /*ARGSUSED*/
  194. evalbuffer(f, n, k) {
  195.     register LINE    *lp;
  196.     register BUFFER    *bp = curbp;
  197.     register int    s;
  198.     static char    excbuf[NKBDM];
  199.     char        *strncpy();
  200.  
  201.     for (lp = lforw(bp->b_linep); lp != bp->b_linep; lp = lforw(lp)) {
  202.         if (llength(lp) >= NKBDM + 1) return FALSE ;
  203.         (VOID) strncpy(excbuf, ltext(lp), NKBDM);
  204.         if ((s = excline(excbuf)) != TRUE) return s;
  205.     }
  206.     return TRUE;
  207. }
  208. /*
  209.  * evalfile - go get a file and evaluate it as line commands. You can
  210.  *    go get your own startup file if need be.
  211.  */
  212. /*ARGSUSED*/
  213. evalfile(f, n, k) {
  214.     register int    s;
  215.     char        fname[NFILEN];
  216.  
  217.     if ((s = ereply("Load file: ", fname, NFILEN)) != TRUE)
  218.         return s;
  219.     return load(fname);
  220. }
  221.  
  222. /*
  223.  * load - go load the file name we got passed.
  224.  */
  225. load(fname) char *fname; {
  226.     register int    s;
  227.     char        excbuf[NKBDM];
  228.  
  229.     if (((s = ffropen(fname)) == FIOERR) || (s == FIOFNF))
  230.         return FALSE;
  231.     while ((s = ffgetline(excbuf, NKBDM)) == FIOSUC)
  232.         if (excline(excbuf) != TRUE) break;
  233.     (VOID) ffclose();
  234.     return s == FIOEOF;
  235. }
  236.  
  237. /*
  238.  * excline - run a line from a load file or eval-expression.
  239.  */
  240. excline(line) register char *line; {
  241.     register char    *funcp, *argp = NULL;
  242.     char        *skipwhite(), *parsetoken(), *backquote();
  243.     int        status;
  244.  
  245.     /* Don't know if it works; don't care - mwm */
  246.     if (kbdmip != NULL || kbdmop != NULL) {
  247.         ewprintf("Not now!") ;
  248.         return FALSE;
  249.     }
  250.  
  251.     funcp = skipwhite(line);
  252.     if (*funcp == '\0') return TRUE;    /* No error on blank lines */
  253.     line = parsetoken(funcp);
  254.     if (*line != '\0') {
  255.         *line++ = '\0';
  256.         line = skipwhite(line);
  257.         if ((*line >= '0' && *line <= '9') || *line == '-') {
  258.             argp = line;
  259.             line = parsetoken(line);
  260.         }
  261.     }
  262.  
  263.     kbdmip = &kbdm[0];
  264.     if (argp != NULL) {
  265.         *kbdmip++ = (KEY) (KCTRL|'U');
  266.         *kbdmip++ = (KEY) atoi(argp);
  267.     }
  268.     *kbdmip++ = (KEY) (KMETA|'X');
  269.     /* Pack in function */
  270.     while (*funcp != '\0')
  271.         if (kbdmip+1 <= &kbdm[NKBDM-3]) *kbdmip++ = (KEY) *funcp++;
  272.         else {
  273.             ewprintf("eval-expression macro overflow");
  274.             ttflush();
  275.             return FALSE;
  276.         }
  277.     *kbdmip++ = '\0';    /* done with function */
  278.     /* Pack away all the args now...    */
  279.     while (*line != '\0') {
  280.         argp = skipwhite(line);
  281.         if (*argp == '\0') break ;
  282.         line = parsetoken(argp) ;
  283.         /* Slightly bogus for strings. But they should be SHORT! */
  284.         if (kbdmip+(line-argp)+1 > &kbdm[NKBDM-3]) {
  285.             ewprintf("eval-expression macro overflow");
  286.             ttflush();
  287.             return FALSE;
  288.         }
  289.         if (*line != '\0') *line++ = '\0';
  290.         if (*argp != '"') {
  291.             if (*argp == '\'') ++argp;
  292.             while (*argp != '\0')
  293.                 *kbdmip++ = (KEY) *argp++;
  294.             *kbdmip++ = '\0';
  295.         }
  296.         else {    /* Quoted strings special again */
  297.             ++argp;
  298.             while (*argp != '"' && *argp != '\0')
  299.                 if (*argp != '\\') *kbdmip++ = (KEY) *argp++;
  300.                 else argp = backquote(++argp, TRUE);
  301.             /* Quotes strings are gotkey'ed, so no trailing null */
  302.         }
  303.     }
  304.     *kbdmip++ = (KEY) (KCTLX|')');
  305.     *kbdmip++ = '\0';
  306.     kbdmip = NULL;
  307.     status = ctlxe(FALSE, 1, KRANDOM);
  308.     kbdm[0] = (KCTLX|')');
  309.     return status;
  310. }
  311. /*
  312.  * a pair of utility functions for the above
  313.  */
  314. char *
  315. skipwhite(s) register char *s; {
  316.  
  317.     while ((*s == ' ' || *s == '\t' || *s == ')' || *s == '(')
  318.         && *s != '\0')
  319.         if (*s == ';') *s = '\0' ;
  320.         else s++;
  321.     return s;
  322. }
  323.  
  324. char *
  325. parsetoken(s) register char *s; {
  326.  
  327.     if (*s != '"')
  328.         while (*s != ' ' && *s != '\t' && *s != '(' && *s != ')'
  329.             && *s != '\0') {
  330.             if (*s == ';') *s = '\0';
  331.             else s++;
  332.         }
  333.     else    /* Strings get special treatment */
  334.         do {
  335.             /* Beware: You can \ out the end of the string! */
  336.             if (*s == '\\') ++s;
  337.             if (ISLOWER(*s)) *s = TOUPPER(*s);
  338.             } while (*++s != '"' && *s != '\0');
  339.     return s;
  340. }
  341. /*
  342.  * Put a backquoted string element into the keyboard macro. Return pointer
  343.  * to char following backquoted stuff.
  344.  */
  345. /* Don't want to get the objects in isdigit.c just for this */
  346. #define    isdigit(c)    (((c) >= '0') && ((c) <= '9'))
  347.  
  348. char *
  349. backquote(in, flag) char *in; {
  350.     register KEY    keycode;
  351.  
  352.     switch (*in++) {
  353.         case 'T': *kbdmip++ = (KEY) (KCTRL|'I');
  354.               break;
  355.         case 'N': *kbdmip++ = (KEY) (KCTRL|'J');
  356.               break; 
  357.         case 'R': *kbdmip++ = (KEY) (KCTRL|'M');
  358.               break;
  359.         case '^': *kbdmip = (KEY) (KCTRL|*in++);
  360.               if (flag != FALSE && *kbdmip == (KEY) (KCTRL|'X')) {
  361.                   if (*in == '\\') in = backquote(++in, FALSE);
  362.                   else *kbdmip++ = (KEY) *in++;
  363.                   kbdmip[-1] |= (KEY) KCTLX;
  364.               } else ++kbdmip;
  365.               break;
  366.         case 'E':
  367.               if (flag != TRUE) *kbdmip++ = (KEY) (KCTRL|'[');
  368.               else if (*in != '\\') *kbdmip++ = (KEY) (KMETA|*in++);
  369.               else {
  370.                   in = backquote(++in, FALSE);
  371.                   kbdmip[-1] |= (KEY) KMETA;
  372.               }
  373.               break;
  374.  
  375.         /* (L. Frenkel) Convert "\Fd" and "\Fdd" to a function
  376.          * key code between KFIRST and KLAST. "dd" should be
  377.          * decimal; codes > KLAST are mapped to KLAST, for want
  378.          * of a better idea of what to do with them.
  379.          */
  380.         case 'F':
  381.                         keycode = 0;
  382.             if (isdigit(*in))
  383.                 keycode += *in++ - '0';
  384.             if (isdigit(*in))
  385.                 keycode = (10 * keycode) + *in++ - '0';
  386.             if ( (keycode += KFIRST) > KLAST)
  387.                 keycode = KLAST;
  388.             *kbdmip++ = (KEY) keycode;
  389.                 break;
  390.     }
  391.     return in;
  392. }
  393. #endif    STARTUP
  394.